﻿using System;
using System.Windows.Forms;
using AudioEngine;

namespace AudioCompare
{
    public partial class frmMain : Form
    {
        WaveFile file1 = null;
        WaveFile file2 = null;

        public frmMain()
        {
            InitializeComponent();
        }

        private void btn1_Click(object sender, EventArgs e)
        {
            try {
                OpenFileDialog fd = new OpenFileDialog();
                fd.Filter = "Wav File | *.wav";
                fd.CheckFileExists = true;
                if (fd.ShowDialog() != DialogResult.OK) return;
                txtPath1.Text = fd.FileName;
                file1 = new WaveFile(fd.FileName);
                w1.WaveFile = file1;
                w1.Refresh();
                lbInfo1.Text = file1.BPS + " Bps  \r\n" + file1.Duration + " Duration  \r\n" + file1.NSamples + " samples  \r\n" + file1.SampleRate + " Hz  \r\n" + file1.NChannels + " channels";
            } catch (Exception ex) {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                file1 = null;
            }
            CheckAnalyzeCanStart();
        }

        private void btn2_Click(object sender, EventArgs e)
        {
            try {
                OpenFileDialog fd = new OpenFileDialog();
                fd.Filter = "Wav File | *.wav";
                fd.CheckFileExists = true;
                if (fd.ShowDialog() != DialogResult.OK) return;
                txtPath2.Text = fd.FileName;
                file2 = new WaveFile(fd.FileName);
                w2.WaveFile = file2;
                w2.Refresh();

                lbInfo2.Text = file2.BPS + " Bps  \r\n" + file2.Duration + " Duration  \r\n" + file2.NSamples + " samples  \r\n" + file2.SampleRate + " Hz  \r\n" + file2.NChannels + " channels";
                //    cbChan1.Items.Clear();
                //for (int i = 0; i < file1.NChannels; i++)
                //    cbChan1.Items.Add(i.ToString());
                //cbChan1.SelectedIndex = 0;
            } catch (Exception ex) {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                file2 = null;
            }
            CheckAnalyzeCanStart();
        }

        void CheckAnalyzeCanStart()
        {
            btnStart.Enabled = false;
            if (file1 == null || file2 == null) return;
            btnStart.Enabled = true;
        }

        /// <summary>
        /// 样本重叠率计算
        /// </summary>
        /// <param name="iInterval">抽样间隔，值越小匹配越精确</param>
        /// <param name="iWP"></param>
        public void DetectBestOverlap(int iInterval, WorkProgress iWP)
        {
            float CrossCorr = 0, BestCrossCorr = 0;
            int bestI = 0;
            statusBar.Text = "Detecting best overlap interval...";
            //比较Channel,默认为0
            float[] data1 = file1.GetData()[0];
            float[] data2 = file2.GetData()[0];
            for (int i = -iInterval; i < iInterval; i++) {
                CrossCorr = MathLib.CrossCorrelation(data1, data2, i);
                if (CrossCorr > BestCrossCorr) {
                    BestCrossCorr = CrossCorr;
                    bestI = i;
                    lbBestOverlap.Text = i.ToString();
                    lbBestOverlap.Refresh();
                }
                iWP.UpdateProgress(100 * (i + iInterval) / 2 / iInterval);
            }
            if (bestI == 0) return;

            if (bestI > 0)
                file2.SkipFirstSamples((uint)bestI);
            else
                file1.SkipFirstSamples((uint)Math.Abs(bestI));
            lbInfo1.Text = file1.NSamples.ToString() + " samples";
            lbInfo2.Text = file2.NSamples.ToString() + " samples";
            w1.Refresh(); w2.Refresh();
        }

        /// <summary>
        /// 时间域对比
        /// </summary>
        /// <param name="iWP"></param>
        public void AnalyzeTime(WorkProgress iWP)
        {
            statusBar.Text = "Time Domain Analysis...";
            float[] difArr;
            float[] data1 = file1.GetData()[0];
            float[] data2 = file2.GetData()[0];
            iWP.UpdateProgress(0);
            UInt32 len = Math.Min(file1.NSamples, file2.NSamples);
            uint skip = 100;
            UInt32 c = 0;
            difArr = new float[len / skip + 1];
            for (UInt32 i = 0; i < len; i += skip, c++) {
                float avg = 0;
                for (UInt32 n = 0; n < skip && i + n < len; n++)
                    avg += Math.Abs(data1[i + n] - data2[i + n]);
                avg /= skip;
                difArr[c] = avg * 100 / file1.MaxAllowableValue;
                if (c % 10 == 0) {
                    iWP.UpdateProgress((int)(i * 100 / len));
                }
            }
            lbAvgErr.Text = Math.Round(MathLib.ArrayAverage(difArr, difArr.Length), 5).ToString();
        }

        /// <summary>
        /// 对wave文件进行处理
        /// </summary>
        /// <param name="iThr"></param>
        public void TrimWaves(int iThr)
        {
            UInt32 m1a, m1b, m2a, m2b;
            statusBar.Text = "Trimming Waveforms...";
            file1.Trim(iThr * file1.MaxAllowableValue / 100, false, out m1a, out m1b);
            file2.Trim(iThr * file2.MaxAllowableValue / 100, false, out m2a, out m2b);
            lbInfo1.Text = file1.NSamples.ToString() + " samples";
            lbInfo2.Text = file2.NSamples.ToString() + " samples";
            w1.Refresh(); w2.Refresh();
        }

        /// <summary>
        /// 开始对比
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            WorkProgress wp = new WorkProgress();
            wp.PBar = tooleProgressBar;
            TrimWaves(0);
            //检测最佳重叠
            DetectBestOverlap(50, wp);
            //  AnalyzeTime(wp);
            int Threshold = 85;
            string strBestOverlap = txtThreshold.Text.Trim();
            if (int.TryParse(strBestOverlap, out Threshold)) { }
            CheckResult(Threshold);
        }

        /// <summary>
        /// 根据样本重叠率来计算音频相似度
        /// </summary>
        /// <param name="Threshold">匹配阈值</param>
        private void CheckResult(int Threshold)
        {
            int bestOverlap = -1;
            string strBestOverlap = lbBestOverlap.Text.Trim();
            if (int.TryParse(strBestOverlap, out bestOverlap)) {
                if (bestOverlap >= 0) {
                    bestOverlap = 100 - bestOverlap;
                    strBestOverlap = bestOverlap + "%";
                    if (bestOverlap >= Threshold) {
                        labResult.Text = "匹配成功(相似度:" + strBestOverlap + ").";
                        return;
                    } else {
                        labResult.Text = "匹配失败(相似度:" + strBestOverlap + ").";
                        return;
                    }
                }
            }
            labResult.Text = "匹配失败(相似度:0%).";
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            CheckAnalyzeCanStart();
        }
    }
}
